﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace CKSE.ViewModels
{
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        #region Events
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region Fields
        private bool _disposed;
        private string _displayName;
        #endregion

        #region Properties
        public virtual string DisplayName
        {
            get
            {
                return _displayName;
            }
            protected set
            {
                if (_displayName != value)
                {
                    _displayName = value;
                    OnPropertyChanged("DisplayName");
                }
            }
        }

        protected virtual bool ThrowOnInvalidPropertyName
        {
            get;
            private set;
        }
        #endregion

        #region Life cycle
        public ViewModelBase()
        {
            _disposed = false;
        }

#if DEBUG
        /// <summary>
        /// Useful for ensuring that ViewModel objects are properly garbage collected.
        /// </summary>
        ~ViewModelBase()
        {
            string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
            System.Diagnostics.Debug.WriteLine(msg);
        }
#endif
        #endregion

        #region Methods
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);                
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                OnDispose();
                if (disposing)
                {
                    Debug.WriteLine("ViewModelBase object disposed");
                }
                _disposed = true;
            }
        }

        public virtual void OnDispose()
        {
            
        }

        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            if (string.IsNullOrWhiteSpace(propertyName) || string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }

            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string message = string.Format("Property name \"{0}\" is invalid !", propertyName);
                if (ThrowOnInvalidPropertyName)
                {
                    throw new Exception(message);
                }
                else
                {
                    Debug.Fail(message);
                }
            }
        }
        
        protected virtual void OnPropertyChanged(string propertyName)
        {
            VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}
